Control Structures
In the previous three instalments of this column I’ve described how to define and use
SPEED/ASM variables and how to perform the standard integer arithmetic operations,
and I’ve discussed some 6502 code necessary to write complete SPEED/ASM programs.

With most of the basics,
     behind us, its’ time to begin a consideration of SPEED/ASM’s control structures.

The FOR. ..NEXT Loop
SPEED/ASM supports two variations on Basic’s FOR...NEXT :loop: FOR and FOR0.
The FOR subroutine is a generalized FOR loop that allows variable initial/ending values
and a step-size.

The FOR0. routine is a specialized version of FOR that assumes the initial and ending
values are constants and that the step-size is one.

Since the FOR0 loop is used better than 90 percent of the time, I will describe it first.

  The FOR0 loop uses the structure:

      JSR FOR0
      ADR IVAR,STARTVAL,ENDVAL

; Body of loop

      JSR NEXT

  IVAR must be the name of a SPEED/ASM integer variable;

STARTVAL and ENDVAL must be integer constants.

      10 FOR I=1 TO 20
      20 PRINT “I= ”;I
      30 NEXT I
      40 END

   Listing 1a, Sample Basic FOR...NEXT routine.

If you specify a SPEED/ASM variable name for STARTVAL or ENDVAL, SPEED/ASM will use the
address of the variable, not the contents of the variable, as the initial or final value.

Since most FOR loops take the form:

      FOR I=1 TO 10

the FOR0 routine turns out to be quite adequate for most applications.
See Listing 1 for a sample Basic FOR... NEXT routine and its SPEED/ASM equivalent.


      EXIT      EQU $FF69
      ;
                JSR INIT      ; Alway before running a SPEED/ASM PGM.
                JSR FOR0
                ADR I,1,20
      ;
      ; Body of Loop
      ;
                JSR PRINT
                BYT "I= ",0
                JSR PRINT
                ADR I
                LDA #CR       ; Print the return at the end
                JSR PUTC      ; of the line.
      ;
                JSR NEXT
                JMP EXIT
      ;
      ; Variable declaration(s)
      ;
      I         ADR 0
                END

          Listing 1b. SPEED/ASM


                JSR FOR0
                ADR I,1,10
      ;
      ; Body of loop
      ;
                JMP EXITLP
      ;
                JSR NEXT
                JMP DIDNTXIT
      ;
      ; Exit condition at this point
      ;
      EXITLP    PLA
                PLA
                PLA
                PLA
                PLA
                PLA
                PLA
                PLA
      ;
      DIDNTXIT:

Listing 2. Popping data off a stack.

As in Basic, it is illegal to jump into the middle. of a FOR. ..NEXT loop in SPEED/ASM.
Unlike Basic, SPEED/ASM isn’t nice enough to tell you that you’ve executed a NEXT without
a matching FOR.
Instead, the system simply hangs up (or begins doing bizarre things to the screen or
accessing your peripheral devices).

Therefore, you should always make sure that there are no jumps into the range of a FOR loop.

For example, the following is definitely forbidden:

            JMP ENTERFOR ;Can’t do!
            JSR FOR0
            ADR I,1,10
      ;
      ENTERFOR:
      ;
            JSR NEXT
      ;

It is in equally bad taste to jump outside the range of a FOR...NEXT loop from within a FOR loop.

Basic also disallows this, but is much more forgiving.

The latter won’t catch the error until you overflow the FOR... NEXT stack (by doing it too many times).

SPEED/ASM, on the other hand, explodes spectacularly the next time you execute an RTS or
otherwise attempt to access the top of the stack.

The reason a jump into or out of a FOR. ..NEXT loop causes problems is that the FOR subroutine
pushes data onto the top of the stack and leaves it there.

This data is popped off and processed by the NEXT subroutine later on.

Obviously, if you call the FOR routine from within a subroutine and then execute an RTS
without first completing the loop by calling the NEXT routine, the 6502 will attempt to
use the data pushed onto the stack by the FOR routine as the return address.

Typically this will not return you to the spot you’re interested in.

For those of you who regularly use the POP command in Applesoft, yes, you can pop this
data off the stack and prematurely exit a FOR...NEXT loop.
The SPEED/ASM FOR. ..NEXT loop pushes 8 bytes of data onto the stack so you can repair
the stack by popping 8 bytes off.

This is accomplished by executing eight PLA instructions in a row. See Listing 2.

The FOR subroutine is similar to the FOR0 subroutine.
The major difference is that the FOR subroutine allows variable starting and ending
values and a variable step-size.

The exact syntax for the FOR subroutine is:

      JSR FOR
      ADR <index var>,<start var>, <end var>,<step var>

where index var is the name of the variable used as the loop index, start var is the name
of the variable containing the starting value, end var is the name of the variable
containing the ending value, and step var is the name of the variable containing the stepsize.

To simulate the Basic statements:

      10 FOR I = J TO K STEP STP
      20 NEXT I

you would use the SPEED/ASM code:

      JSR FOR
      ADR I,J,K,STP

      JSR NEXT

Note that the FOR loop accepts only variable names; constants are not allowed.
If either the starting or ending value must be a variable, or your loop requires a step-size,
then you must use a FOR loop and all the values must be specified as variables.

   For example, consider the Basic loop:

      10 FOR I = J TO 100
      20 NEXT I

Because the starting value (J) is specified as a variable, the FOR0 routine cannot be used.

The FOR routine, however, requires that the starting, ending and step-size values all be
specified as variables.

Therefore, to convert the statement above into SPEED/ASM code you will need to create
two “dummy” variables:

one to hold the ending value constant (100) and one to hold the step-size constant (1).

Use the code in Listing 3.

Note that the constants/variables C100 and C1 are sandwiched between a JMP instruction
and the beginning of the loop.

Since these values are static (they do not change) they should be incorporated into the
code instead of standing at the end of the program with the variables.

Although they are constant values they still must not be executed as 6502 instructions.

Hence, a JMP instruction was executed to skip past the constants.

The FOR subroutine is very powerful, even though it may be somewhat cumbersome to use if
the starting, ending and/or step-size values are constants instead of variables.

The inconvenience is actually minimal since most of the time the FOR0 subroutine is used
instead of the FOR subroutine.

             JMP STRTLP
      C100   ADR 100
      C1     ADR 1
      ;
      STRTLP JSR FOR
             ADR I,J,C100,C1
      ;
      ;Body of loop
      ;
             JSR NEXT

         Listing 3. A FOR routine using “dummy” variables.

       1 J=2
       5 I=1
      10 IF I > = 10 THEN GOTO 20
      11 I=I*J
      12 GOTO 10
      20 END

   Listing 4a. Sample Basic IF routine incorporating a GOTO statement.

      EXIT EQU $FF69
      ;
           JSR INIT
           JSR LOAD
           ADR 2,J
           JSR LOAD
           ADR 1,I
      L10  JSR IFI0
           ADR I,GE,10
           BTR L20
           JSR MUL
           ADR I,J,I
           JMP L10
      ;
      L20  JMP EXIT
           END

    Listing 4b. SPEED/ASM equivalent using BTR.


The SPEED/ASM IFI And IFI0 Routines
SPEED/ASM uses two routines to compare integer values: IFI and IFI0.
IFI compares two integer variables; IFIO compares an integer variable to an integer constant.
Six types of comparison are possible.

The IFI and IFI0 routines return “true” if a comparison holds, “false” if it does not.

You can call the IFI0 routine with the format:

      JSR IFI0
      ADR <var1>,<op>,<value>

where var1 is a SPEED/ASM integer variable, value is any integer constant, and op is the
operator specifying which comparison to perform.

The latter may be:

EQ—test for equality;
NE—test for inequality;
LT—test for less than;
LE—test for less than or equal to;
GT—test for greater than;
or GE—test for greater than or equal to.

For example, to see if IVAR is less than 4376 use the statement:

      JSR IFI0
      ADR IVAR,LT,4376

The EQ, NE, GT, GE, LT and LE symbols are defined for you in SPEED/ASM Equates, Listing 7.
Refer there for the values corresponding to these symbols.

The IFI0 and IFI routines return “true” or “false” in the 6502 accumulator
(where true =1 and false =0), and set the 6502 z bit in the P register so that the BTR and BFL
(branch-if-true and branch-if-false) instructions can be used immediately after the call
to IFI0 or IFI.

To emulate the Basic IF statement you need only add a branch statement to the IFI0 or IFI
statement to make it fully functional.

Refer to Listing 4 for an example.

     IF I< >10 THEN J= -I

   Listing 5a. Sample Basic IF routine.

            JSR IFI0
            ADR I,NE,10
            BFL INE10
            JSR MOVE
            ADR I,J
            JSR NEG
            ADR J
      ;
      INE10:

Listing 5b. SPEED/ASM equivalent using BFL.

This relatively complete SPEED/ASM program (it still needs the SPEED/ASM equates at the top)
exactly duplicates the BASIC program.

Note that the BTR (branch-if-true) instruction branches if the condition I > = 10 is true.

Sometimes you may want to execute and instruction other than a GOTO if an expression is true.

For example,

both Integer Basic and AppleSoft Basic allow IF statements of the for IF <cond> THEN <statement>.

This is easily simulated in SPEED/ASM by using the BFL (branch-if-false) instruction to
branch around the statement you wish to execute.

Listing 5 illustrates SPEED/ASM code of this type and Basic equivalent.

In addition to setting the 6502 Z-flag so that the BTR and BFL instructions can be used
after an IFI0 instruction, the IFI0 routine returns "false" or "true" (0 or 1)
in the 6502 accumulator register.

This feature can be applied to several situations.

Consider the Basic statement I = J< = 10.

This assignment stores 0 info I if J is not less than or equal to ten;

it stores 1 into I if J is less than or equal to ten.

This action can easily be accomplished using the SPEED/ASM statements that follow:

      JSR IFI0
      ADR J,LE,10
      STA I
      LDA /0
      STA I+1

Don't forget that the high order byte of I must be set to 0.

The LDA /0 and STA I+1 statements take care of this problem.

You use the IFI routine to compare two integer variables.

IFI's syntax is almost identical to that of IFI0.
The only difference is that you specify a second SPEED/ASM variable instead of a numeric constant.

The format for the IFI routine is:

      JSR IFI
      ADR <var1>,<op>,<var2>

Interfacing to Apple DOS
  While I could go on discussion how the FOR and IF subroutines work, the best way to
  explain their use is through some concrete examples.
 
Listing 6 uses FOR and IF to demonstrate how to create and access text files under Apple DOS.

As in Basic,
in order to interface to Apple DOS you must print a control-D followed by a DOS command.

Normally, Apple DOS only allows text files to be accessed from a running Basic program.

Since SPEED/ASM is definitely not Basic, we must trick DOS into thinking that a Basic
program is running.

This is easily accomplished by storing the value $80 into locations $75 and $D9 in the
Apple’s 0 page memory space.

This feat is accomplished using the 6502 code:

      LDA #$80
      STA $75
      STA $D9

Storing $80 into location $D9 tells DOS that an Integer Basic program is running;
storing $80 into location $75 informs DOS that an Applesoft program is running.

Whenever DOS receives a command to manipulate a text file it looks to see which Basic is
currently active and then checks the appropriate 0 page location to determine whether
or not the Basic is running.

If location $75 contains $FF and Applesoft is active
 or if location $D9 is positive (less than $80) and Integer Basic is active,
 then a NOT DIRECT COMMAND error is issued and everything stops.
 
 Since many SPEED/ASM programs will be running under the control of Apple DOS,
 the SPEED/ASM INIT routine automatically stores $80 into locations $D9 and $75 for you.
 
 While this is ideal for Apple DOS users, if attempting to run your SPEED/ASM program under
 a different operating system (like ANIX, OS/A, or APEX) you should be aware of the fact
 that SPEED/ASM manipulates these two locations on power-up.

This month’s demonstration program is quite simple.
It writes out a sequence of numbers to a random access file and then reads them back,
displaying them on the screen.

Next month I will begin discussing string variables and expand this sample program into a
mini database/mailing list program.
